/*
 moxl - Modular XML Library
 Copyright (c) 2007, Malcolm Sparks

 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License
 as published by the Free Software Foundation; either version 2
 of the License, or (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package moxl.parser.markup;

import moxl.parser.ParserException;
import moxl.parser.markup.states.XmlParserContext;
import moxl.parser.markup.states.XmlParserState;
import moxl.parser.markup.types.EndOfDocumentMarkup;
import moxl.tokenizer.TokenStream;
import moxl.tokenizer.TokenizerException;

public class MarkupStream
{
	private final XmlParserContext ctx = new XmlParserContext();
	private final TokenStream tstream;

	public MarkupStream(TokenStream tstream)
	{
		this.tstream = tstream;
	}

	/**
	 * @return a new {@link Markup} instance, or an {@link moxl.parser.markup.types.EndOfDocumentMarkup} instance if there is no more markup in this stream.
	 * @throws ParserException
	 * @throws TokenizerException
	 */
	public Markup read() throws ParserException, TokenizerException
	{
		return assembleMarkupFromStream(tstream);
	}

	private final WellFormedTracker wellFormedTracker = new WellFormedTracker();

	private Markup assembleMarkupFromStream(TokenStream tstream) throws ParserException, TokenizerException
	{
		Markup markup = ctx.getState().getDelegate().parseNextMarkupFromStream(tstream, ctx);
		if (markup != null)
		{
			wellFormedTracker.accept(markup);

			if (ctx.getState() == XmlParserState.ELEMENT_CONTENT && wellFormedTracker.elementMarkupStack.isEmpty())
			{
				ctx.changeState(XmlParserState.POSTAMBLE);
			}

			return markup;
		}
		else
		{
			throw new ParserException("Internal error: The DocumentState '" + ctx.getState() + "' has returned null, against coding conventions.", tstream.getPosition());
		}
	}

	public void drain() throws ParserException, TokenizerException
	{
		Markup markup;
		do
		{
			markup = read();
		}
		while (!(markup instanceof EndOfDocumentMarkup));
	}
}
